/*
 * Composition Knowledge Miner. A data mashup composition knowledge miner
 * Copyright (C) 2011 Carlos Rodriguez
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package eu.ict_omelette.mashup.compositionminer;

import eu.ict_omelette.mashup.canonicalmodel.CanonicalMashup;
import eu.ict_omelette.mashup.canonicalmodel.Component;
import eu.ict_omelette.mashup.canonicalmodel.InputParameter;
import eu.ict_omelette.mashup.compositionminer.util.Carpenter;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;

/**
 *
 * @author carlos
 */
public class ParameterValueMiner {
    private LinkedList<CanonicalMashup> compRepo;
    private static String ITEM_SEPARATOR = "&&#&&";
    
    public ParameterValueMiner(LinkedList<CanonicalMashup> compRepo){
        this.compRepo = compRepo;
    }

    public List<CanonicalMashup> mine(Double minSupp){
        LinkedList result = new LinkedList();
        Iterator<CanonicalMashup> repoIt = this.compRepo.iterator();

        LinkedHashMap<String, LinkedList<String>> allCompTypes = new LinkedHashMap();

        int paramCount = 0;

        //Here we get all the component instances by component type. For that, we use
        //a hash table where the key=componentType and value is a LinkedList with the
        //list of all component instances
        while(repoIt.hasNext()){
            CanonicalMashup cm = repoIt.next();

            LinkedHashMap<String, LinkedList<Component>> auxCompTypes = new LinkedHashMap();

            Iterator<Component> itComp = cm.getComponents();
            while(itComp.hasNext()){
                Component comp = itComp.next();

                LinkedList<Component> llInst = auxCompTypes.get(comp.getType());
                if(llInst == null){
                    llInst = new LinkedList();
                    auxCompTypes.put(comp.getType(), llInst);
                }

                llInst.add(comp);
            }

            Iterator<String> itCmpType = auxCompTypes.keySet().iterator();
            while(itCmpType.hasNext()){
                String strCmpType = itCmpType.next();

                //Here we get all the instances of strCmpType in the current mashup
                LinkedList<Component> llauxComp = auxCompTypes.get(strCmpType);

                //We check if there is an entry for this cmpType in the allCompTypes
                LinkedList<String> allInst = allCompTypes.get(strCmpType);
                if(allInst == null){
                    allInst = new LinkedList();
                    allCompTypes.put(strCmpType, allInst);
                }

                String strItemset = "";

                for(int j = 0; j < llauxComp.size(); j++ ){
                    Component comp = llauxComp.get(j);
                    Iterator<InputParameter> itIp = comp.getInputParameters();
                    while(itIp.hasNext()){
                        InputParameter ip = itIp.next();

                        String pName = ip.getName();
                        String pValue = ip.getValue();

                        if(ip.getValue() == null)
                            continue;

                        pName = pName.trim();
                        pValue = pValue.trim();

                        if(pValue.equals(""))
                            continue;

                        String paramName = ip.getName();
                        String paramValue = ip.getValue();

                        paramName = paramName.replaceAll("\\d", "");
                        paramName = paramName.replaceAll("_", "");

                        //We change everything to lower case to make user we have the same
                        //hash function value
                        paramValue = paramValue.toLowerCase();

                        strItemset += paramName + "=>" + paramValue;

                        //We use a special carater to separate each item in the itemset
                        strItemset += ITEM_SEPARATOR;

                    }
                }

                if(!strItemset.trim().equals(""))
                    allInst.add(strItemset);

            }


        }


        //Here we take tha hash table created above and do itemset mining to mine
        //patterns for each component type
        Iterator<String> itKeys = allCompTypes.keySet().iterator();
        while(itKeys.hasNext()){
            String key = itKeys.next();

            LinkedList<String> llInst = allCompTypes.get(key);

            if(llInst.size() <= 0)
                continue;

            //System.out.println(key);


            int idx = 0;
            LinkedHashMap<String, Integer> hashStrToIdx = new LinkedHashMap();
            LinkedHashMap<Integer, String> hashIdxToStr = new LinkedHashMap();
            for(int i = 0; i < llInst.size(); i++){
                String itemset = llInst.get(i);

                String[] items = itemset.split(ITEM_SEPARATOR);

                for(String item: items){
                    if(item.equals(""))
                        continue;

                    //System.out.print(item + "   ");
                    if(hashStrToIdx.get(item) == null){
                        hashStrToIdx.put(item, idx);
                        hashIdxToStr.put(idx, item);
                        idx++;
                    }
                }

                //System.out.println();
            }


            String[] strDB = new String[llInst.size()];
            for(int i =0; i < llInst.size(); i++){
                String strItemset = "";
                String itemset = llInst.get(i);
                String[] items = itemset.split(ITEM_SEPARATOR);

                for(String item: items){
                    if(item.equals(""))
                        continue;

                    idx = hashStrToIdx.get(item);
                    strItemset += idx + " ";


                }

                strItemset = strItemset.trim();
                strDB[i] = strItemset;

                //System.out.println(strItemset);
            }

            try{
                Carpenter car = new Carpenter(strDB, minSupp);
                List listPatterns = car.mine();

                Iterator<int[]> itList = listPatterns.iterator();
                while(itList.hasNext()){
                    int[] itemset = itList.next();

                    CanonicalMashup cm = new CanonicalMashup();
                    cm.setId("");
                    cm.setName("");
                    cm.setSrc("");

                    Component comp = new Component();
                    comp.setId("");
                    comp.setName(key);
                    comp.setType(key);
                    comp.setIsEmbedding(false);

                    cm.addComponent(comp);

                    for(int item : itemset){
                        String strItem = (String)hashIdxToStr.get(item);

                        String[] nameValuePair = strItem.split("=>");
                        String paramName = nameValuePair[0];
                        String paramValue = nameValuePair[1];

                        InputParameter ip = new InputParameter();
                        ip.setName(paramName);
                        ip.setValue(paramValue);

                        comp.addInputParameter(ip);                        
                    }

                    result.add(cm);
                    
                }

            }catch(Exception e){
                e.printStackTrace();
            }
        }

        return result;
    }

}
